package com.demo.lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by hunter
 *
 * @Description 可重入锁又名递归锁，是指在同一个线程在外层方法获取锁的时候，再进入该线程的内层方法会自动获取锁（前提锁对象得是同一个对象或者class），不会因为之前已经获取过还没释放而阻塞。
 *              Java中ReentrantLock和synchronized都是可重入锁，可重入锁的一个优点是可一定程度避免死锁。
 */
public class Reentrant1Lock {

    public synchronized void test() {
        System.out.println(Thread.currentThread().getName() + "~~~~ 0");
        test1();
        System.out.println(Thread.currentThread().getName() + "~~~~ 1");
    }

    public synchronized void test1() {
        System.out.println(Thread.currentThread().getName() + "~~~~ 2");
    }

    private Lock lock = new ReentrantLock();

    public void test2() {
        lock.lock();
        System.out.println(Thread.currentThread().getName() + "~~~~ 3");

        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        test3();
        lock.unlock();
    }

    public void test3() {
        // 执行了一个底部的++操作
        lock.lock();
        System.out.println(Thread.currentThread().getName() + "~~~~ 4");

        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 不会因为test3释放锁而因此释放了test2()的锁, 执行了一个底部的--操作
        lock.unlock();
    }

    public static void main(String[] args) {
        Reentrant1Lock lockTest = new Reentrant1Lock();

        // synchronized锁方法的说明性不高, 因为一个线程执行一个synchronized方法时, 其它线程都不允许再访问任何这个类的synchronized方法
        lockTest.test();

        // 这里用lock再说明一次
        new Thread(lockTest::test2).start();
        new Thread(lockTest::test3).start();
    }
}
